import Annotation.myComponent;
import Annotation.myValue;
import Annotation.myAutowired;
import Annotation.myQualifier;
import utils.MyTools;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class MyAnnotationConfigApplicationContext {
    private Map<String,Object> bean = new HashMap<>();
    public MyAnnotationConfigApplicationContext(String pack) {
//扫描报名，得到bean工厂的原材料
        Set<BeanDefinition> beanDefinition = getBeanDefinition(pack);
//        根据bean利用反射动态的创建对象
        createObject(beanDefinition);
//        装载对象
        autowriedObject(beanDefinition);
    }
    public void autowriedObject(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()){
            BeanDefinition beanDefinition = iterator.next();
            Class aClass = beanDefinition.getBeanClass();
            for (Field declaredField : aClass.getDeclaredFields()) {
                if (declaredField.getAnnotation(myAutowired.class) != null){
                    myQualifier qualifier = declaredField.getAnnotation(myQualifier.class);
                    if (qualifier != null){
                        String beanname = qualifier.value();
                        Object bean = getBean(beanname);
                        String fieldName = declaredField.getName();
                        String methodName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                        try {
                            Method method = aClass.getMethod(methodName, declaredField.getType());
                            Object o = getBean(beanDefinition.getBeanName());
                            method.invoke(o,bean);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }else {
                        String name = declaredField.getName();
                        Object bean = getBean(name);
                        System.out.println(bean);
                        String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
                        try {
                            Method method = aClass.getMethod(methodName, declaredField.getType());
                            Object o = getBean(beanDefinition.getBeanName());
                            method.invoke(o,bean);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        }
    }
//    得到容器中的bean
    public Object getBean(String beanName){
        return bean.get(beanName);
    }
    public void createObject(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()){
            BeanDefinition next = iterator.next();
            Class aClass = next.getBeanClass();
            String beanName = next.getBeanName();
            try {
                Object newInstance = aClass.getDeclaredConstructor().newInstance();
//                如果有value注解，则根据注解赋值
                for (Field declaredField : aClass.getDeclaredFields()) {
                    myValue annotation = declaredField.getAnnotation(myValue.class);
                    if (annotation != null){
                        String value = annotation.value();
                        String fieldName = declaredField.getName();
                        String methodName = "set" + fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                        Method method = aClass.getMethod(methodName, declaredField.getType());
                        Object val = null;
                        switch (declaredField.getType().getName()){
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                        }
                        method.invoke(newInstance,val);
                    }
                }

                bean.put(beanName,newInstance);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }
    public Set<BeanDefinition> getBeanDefinition(String pack){
//        扫描
        Set<Class<?>> classes = MyTools.getClasses(pack);
//        得到所有的class对象，判断是否有注解
        Iterator<Class<?>> iterator = classes.iterator();
        Set<BeanDefinition> beanDefinitions = new HashSet<>();
        while (iterator.hasNext()){
            Class<?> aClass = iterator.next();
            myComponent annotation = aClass.getAnnotation(myComponent.class);
            if (annotation != null){
//                如果有注解，则获取beanname
                String beanname = annotation.value();
                if ("".equals(beanname)){
                    String s = aClass.getName().replaceAll(aClass.getPackage().getName() + ".", "");
                    String s1 = s.substring(0, 1).toLowerCase()+s.substring(1);
                    beanname = s1;
                }
                beanDefinitions.add(new BeanDefinition(beanname,aClass));
            }

        }

        return beanDefinitions;
    }
}
